
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SCClient {	
	private static final int END_OF_INPUT = -1;
	private final String hostName;
	private final int portNumber;
	private String message = "";

	private SocketChannel socketChannel;

	/**
	 * ctor
	 * 
	 * @param hostName
	 * @param portNumber
	 * @param clientIdentity
	 */
	public SCClient(String hostName, int portNumber, String message) {
		this.hostName = hostName;
		this.portNumber = portNumber;
		this.message = message;
	}

	/**
	 * ctor without input message ...
	 * 
	 * @param hostName
	 * @param portNumber
	 */
	public SCClient(String hostName, int portNumber) {
		this.hostName = hostName;
		this.portNumber = portNumber;
	}

	/**
	 * start the Client
	 * 
	 * @throws InterruptedException
	 */
	public void startClient() throws InterruptedException {
		try {
			Selector selector = openConnection();

			if (selector.select() > 0) {
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> iterator = keys.iterator();

				if (iterator.hasNext()) {
					SelectionKey selKey = (SelectionKey) iterator.next();
					socketChannel = (SocketChannel) selKey.channel();
					iterator.remove();
					if (selKey.isConnectable()) {
						if (socketChannel.isConnectionPending()) {
							socketChannel.finishConnect();
							System.out
									.println("Client successfuly connected to the server");
						}

						if (message.isEmpty()) {
							sendInputMessage();
						} else {
							sendArgumentMessage(message.getBytes());
						}
						closeConnection();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * read from standard input and send messages
	 * @throws IOException
	 */
	private void sendInputMessage() throws IOException {
		byte[] data = new byte[System.in.available()];
		while(System.in.read(data) != END_OF_INPUT) {
			sendArgumentMessage(data);
		}
	}

	/**
	 * sending a Message to the server
	 * 
	 * @param socketChannel
	 * @param message
	 * @throws IOException
	 */
	private void sendArgumentMessage(byte[] message) throws IOException {
		ByteBuffer buffer = ByteBuffer.wrap(message);
		socketChannel.write(buffer);
		buffer.clear();
	}

	/**
	 * closing connection to the server
	 * 
	 * @param socketChannel
	 */
	private void closeConnection() {
		System.out.println("Closing connections...");
		try {
			socketChannel.socket().close();
			System.out.println("Connection closed!");
		} catch (IOException e) {
			System.out.println("Error while closing connection");
			e.printStackTrace();
		}
	}

	/**
	 * connect to the server
	 * 
	 * @return
	 * @throws IOException
	 * @throws UnknownHostException
	 * @throws ClosedChannelException
	 */
	private Selector openConnection() throws IOException, UnknownHostException,
			ClosedChannelException {
		SocketChannel connection = SocketChannel.open();
		connection.configureBlocking(false);
		connection.connect(new InetSocketAddress(InetAddress
				.getByName(hostName), portNumber));
		Selector selector = Selector.open();
		connection.register(selector, SelectionKey.OP_CONNECT);
		return selector;
	}

	/**
	 * 
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		SCClient client;
		if (args.length == 3) {
			client = new SCClient(args[0], Integer.parseInt(args[1]), args[2]);
			client.startClient();
		} else if (args.length == 2) {
			client = new SCClient(args[0], Integer.parseInt(args[1]));
			client.startClient();
		} else {
			System.out
					.printf("usage: java SCClient hostName portNumber \"Message\"\n");
		}
	}
}
